# load libraries
library(readr)
library(dplyr)
# Loading the csv file
df = read_csv('advertising.csv')
Parsed with column specification:
cols(
  `Daily Time Spent on Site` = col_double(),
  Age = col_double(),
  `Area Income` = col_double(),
  `Daily Internet Usage` = col_double(),
  `Ad Topic Line` = col_character(),
  City = col_character(),
  Male = col_double(),
  Country = col_character(),
  Timestamp = col_datetime(format = ""),
  `Clicked on Ad` = col_double()
)
# Previewing the first five rows of the dataframe
head(df)
# show information on dataset
str(df)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':    1000 obs. of  10 variables:
 $ Daily Time Spent on Site: num  69 80.2 69.5 74.2 68.4 ...
 $ Age                     : num  35 31 26 29 35 23 33 48 30 20 ...
 $ Area Income             : num  61834 68442 59786 54806 73890 ...
 $ Daily Internet Usage    : num  256 194 236 246 226 ...
 $ Ad Topic Line           : chr  "Cloned 5thgeneration orchestration" "Monitored national standardization" "Organic bottom-line service-desk" "Triple-buffered reciprocal time-frame" ...
 $ City                    : chr  "Wrightburgh" "West Jodi" "Davidton" "West Terrifurt" ...
 $ Male                    : num  0 1 0 1 0 1 0 1 1 1 ...
 $ Country                 : chr  "Tunisia" "Nauru" "San Marino" "Italy" ...
 $ Timestamp               : POSIXct, format: "2016-03-27 00:53:11" "2016-04-04 01:39:02" "2016-03-13 20:35:42" ...
 $ Clicked on Ad           : num  0 0 0 0 0 0 0 1 0 0 ...
 - attr(*, "spec")=
  .. cols(
  ..   `Daily Time Spent on Site` = col_double(),
  ..   Age = col_double(),
  ..   `Area Income` = col_double(),
  ..   `Daily Internet Usage` = col_double(),
  ..   `Ad Topic Line` = col_character(),
  ..   City = col_character(),
  ..   Male = col_double(),
  ..   Country = col_character(),
  ..   Timestamp = col_datetime(format = ""),
  ..   `Clicked on Ad` = col_double()
  .. )
# checking for the statistical summary
summary(df)
 Daily Time Spent on Site      Age         Area Income    Daily Internet Usage Ad Topic Line     
 Min.   :32.60            Min.   :19.00   Min.   :13996   Min.   :104.8        Length:1000       
 1st Qu.:51.36            1st Qu.:29.00   1st Qu.:47032   1st Qu.:138.8        Class :character  
 Median :68.22            Median :35.00   Median :57012   Median :183.1        Mode  :character  
 Mean   :65.00            Mean   :36.01   Mean   :55000   Mean   :180.0                          
 3rd Qu.:78.55            3rd Qu.:42.00   3rd Qu.:65471   3rd Qu.:218.8                          
 Max.   :91.43            Max.   :61.00   Max.   :79485   Max.   :270.0                          
     City                Male         Country            Timestamp                  
 Length:1000        Min.   :0.000   Length:1000        Min.   :2016-01-01 02:52:10  
 Class :character   1st Qu.:0.000   Class :character   1st Qu.:2016-02-18 02:55:42  
 Mode  :character   Median :0.000   Mode  :character   Median :2016-04-07 17:27:29  
                    Mean   :0.481                      Mean   :2016-04-10 10:34:06  
                    3rd Qu.:1.000                      3rd Qu.:2016-05-31 03:18:14  
                    Max.   :1.000                      Max.   :2016-07-24 00:22:16  
 Clicked on Ad
 Min.   :0.0  
 1st Qu.:0.0  
 Median :0.5  
 Mean   :0.5  
 3rd Qu.:1.0  
 Max.   :1.0  
# determine the dimensions of the dataset 
dim(df)
[1] 1000   10

The dataset is seen to have 1000 observations and 10 variables.

# checking if there exists null values by calculating the sum of the null values per column 
colSums((is.na(df)))
Daily Time Spent on Site                      Age              Area Income 
                       0                        0                        0 
    Daily Internet Usage            Ad Topic Line                     City 
                       0                        0                        0 
                    Male                  Country                Timestamp 
                       0                        0                        0 
           Clicked on Ad 
                       0 
# a plot showing missing values
library(DataExplorer)
plot_missing(df)

# checking for duplicates in the dataset by assigning a variable 'duplicates'
duplicates <- df[duplicated(df),]
duplicates
# Plotting boxplots
options(repr.plot.width = 13, repr.plot.height = 7)
ggplot(data = df, aes(x = gender, y = daily_internet_usage)) + 
    geom_boxplot(aes(fill = factor(clicked_on_ad))) + 
    labs(title = 'Daily internet usage Vs Gender', y = 'Daily internet usage', x = 'Gender', fill = 'Clicked on ad') +
    scale_color_brewer(palette = 'cool') +
    theme(plot.title = element_text(size = 18, face = 'bold', color = 'darkmagenta'),
             axis.title.x = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.title.y = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.text.x = element_text(size = 13),
             axis.text.y = element_text(size = 13),
             legend.title = element_text(size = 13, color = 'darkmagenta'),
             legend.text = element_text(size = 12))
Unknown palette cool

# a plot showing income usage in relation to gender
options(repr.plot.width = 13, repr.plot.height = 7)
ggplot(data = df, aes(x = gender, y = area_income)) + 
    geom_boxplot(aes(fill = factor(clicked_on_ad))) + 
    geom_dotplot(binwidth = NULL, binaxis = 'y', stackdir = 'center', dotsize = .5, fill = 'maroon') +
    labs(title = 'Area income usage Vs Gender', y = 'Area income', x = 'Gender', fill = 'Clicked on ad') +
    scale_color_brewer(palette = 'cool') +
    theme(plot.title = element_text(size = 18, face = 'bold', color = 'darkmagenta'),
             axis.title.x = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.title.y = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.text.x = element_text(size = 13),
             axis.text.y = element_text(size = 13),
             legend.title = element_text(size = 13, color = 'darkmagenta'),
             legend.text = element_text(size = 12))
Unknown palette cool

# plotting multiple boxplots
options(repr.plot.width = 13, repr.plot.height = 7)
boxplot(df$daily_time_spent_on_site, df$age, df$daily_internet_usage,
main = "Multiple boxplots for comparision",
at = c(1,2,3),
names = c("Site", "Age","Usage"),
las = 2,
col = c("darkmagenta","darkgreen","yellow"),
border = "blue",
horizontal = TRUE,
notch = TRUE
)

# The male column should be renamed to gender
colnames(df)[colnames(df) == 'male'] = 'gender'
library(tidyverse)
# Changing column names to lower case
colnames(df) = tolower(str_replace_all(colnames(df), c(' ' = '_')))

# Checking whether the column names have been renames appriopriately
print(colnames(df))
 [1] "daily_time_spent_on_site" "age"                      "area_income"             
 [4] "daily_internet_usage"     "ad_topic_line"            "city"                    
 [7] "gender"                   "country"                  "timestamp"               
[10] "clicked_on_ad"           
# Checking the datatypes for each column

columns = colnames(df)
for (column in seq(length(colnames(df)))){
    print(columns[column])
    print(str(df[, column]))
    cat('\n')
}
[1] "daily_time_spent_on_site"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ daily_time_spent_on_site: num  69 80.2 69.5 74.2 68.4 ...
NULL

[1] "age"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ age: num  35 31 26 29 35 23 33 48 30 20 ...
NULL

[1] "area_income"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ area_income: num  61834 68442 59786 54806 73890 ...
NULL

[1] "daily_internet_usage"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ daily_internet_usage: num  256 194 236 246 226 ...
NULL

[1] "ad_topic_line"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ ad_topic_line: chr  "Cloned 5thgeneration orchestration" "Monitored national standardization" "Organic bottom-line service-desk" "Triple-buffered reciprocal time-frame" ...
NULL

[1] "city"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ city: chr  "Wrightburgh" "West Jodi" "Davidton" "West Terrifurt" ...
NULL

[1] "gender"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ gender: num  0 1 0 1 0 1 0 1 1 1 ...
NULL

[1] "country"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ country: chr  "Tunisia" "Nauru" "San Marino" "Italy" ...
NULL

[1] "timestamp"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ timestamp: POSIXct, format: "2016-03-27 00:53:11" "2016-04-04 01:39:02" "2016-03-13 20:35:42" ...
NULL

[1] "clicked_on_ad"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ clicked_on_ad: num  0 0 0 0 0 0 0 1 0 0 ...
NULL
library(magrittr)
# Changing column names to their appriopriate data type
# Creating a lists of categorical and numerical columns 

# List of categorical columns
cat_cols = c("ad_topic_line", "city", "gender", "country", "clicked_on_ad" )

# List of numerical columns
num_cols = c("daily_time_spent_on_site", "age", "area_income", "daily_internet_usage")

# Changing columns to factors
df[,cat_cols] %<>% lapply(function(x) as.factor(as.character(x)))
# Checking whether the datatypes for each column have been changed apprippriately
columns = colnames(df)
for (column in seq(length(colnames(df)))){
    print(columns[column])
    print(str(df[, column]))
    print(nlevels(df[, column]))
    cat('\n')
}
[1] "daily_time_spent_on_site"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ daily_time_spent_on_site: num  69 80.2 69.5 74.2 68.4 ...
NULL
[1] 0

[1] "age"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ age: num  35 31 26 29 35 23 33 48 30 20 ...
NULL
[1] 0

[1] "area_income"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ area_income: num  61834 68442 59786 54806 73890 ...
NULL
[1] 0

[1] "daily_internet_usage"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ daily_internet_usage: num  256 194 236 246 226 ...
NULL
[1] 0

[1] "ad_topic_line"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ ad_topic_line: Factor w/ 1000 levels "Adaptive 24hour Graphic Interface",..: 92 465 567 904 767 806 223 724 108 455 ...
NULL
[1] 0

[1] "city"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ city: Factor w/ 969 levels "Adamsbury","Adamside",..: 962 904 112 940 806 283 47 672 885 713 ...
NULL
[1] 0

[1] "gender"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ gender: Factor w/ 2 levels "0","1": 1 2 1 2 1 2 1 2 2 2 ...
NULL
[1] 0

[1] "country"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ country: Factor w/ 237 levels "Afghanistan",..: 216 148 185 104 97 159 146 13 83 79 ...
NULL
[1] 0

[1] "timestamp"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ timestamp: POSIXct, format: "2016-03-27 00:53:11" "2016-04-04 01:39:02" "2016-03-13 20:35:42" ...
NULL
[1] 0

[1] "clicked_on_ad"
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1000 obs. of  1 variable:
 $ clicked_on_ad: Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 2 1 1 ...
NULL
[1] 0
# Frequency tables
# 0-female, 1-male
levels(df$gender) = c("Female", "Male")
table(df$gender)

Female   Male 
   519    481 

The gender column is seen to be almost evenly distributed with Females being slightly higher than the males.

#0-yes,1-no
levels(df$clicked_on_ad) = c("Yes", "No")
table(df$clicked_on_ad)

Yes  No 
500 500 

Exploratory Data Analysis

#This is where we explore the data so as to: maximize insights on the data set uncover underlying structure extract important variables detect outliers and anomalies test underlying assumptions develop models with great explanatory predictive power *determine optimal factor settings

Here we will perform : univariate analysis bivariate analysis multivariate analysis

# Daily time spent on site distribution
#
x = hist(df$daily_time_spent_on_site,
         main = "Daily time Spent on Site",
         xlab = "Daily time Spent on Site",
         col = "cyan",
)

summary(df$daily_time_spent_on_site)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  32.60   51.36   68.22   65.00   78.55   91.43 
# Age distribution.
#
y = hist(df$age,
         main = "Age distribution",
         xlab = "Age",
         col = "purple",
)

summary(df$age)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  19.00   29.00   35.00   36.01   42.00   61.00 

z = hist(df$area_income,
         main = "Area Income distribution",
         xlab = "Area",
         col = "pink",
)

summary(df$area_income)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  13996   47032   57012   55000   65471   79485 
#density plots fr univariate analysis
library(DataExplorer)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
plot_density(df)

# bivariate plots
library(DataExplorer)
timespent <- df$daily_time_spent_on_site
internetusage<- df$daily_internet_usage
plot(timespent, internetusage, xlab="Daily time spent on site", ylab="Daily Internet Usage")

plot(area_income ~ daily_internet_usage, data = df)

library (ggExtra)
options(repr.plot.width = 13, repr.plot.height = 7)
g = ggplot(data =df, aes(x =area_income, y = daily_internet_usage, col= clicked_on_ad)) + 
    geom_count() + 
    labs(title = 'Area income Vs Daily internet usage', y = 'Daily internet usage', x = 'Area income', fill = 'Clicked on ad') +
    scale_color_brewer(palette = 'Set1') +
    theme(plot.title = element_text(size = 18, face = 'bold', color = 'darkmagenta'),
             axis.title.x = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.title.y = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.text.x = element_text(size = 13),
             axis.text.y = element_text(size = 13),
             legend.title = element_text(size = 13, color = 'darkmagenta'),
             legend.text = element_text(size = 13))

ggMarginal(g, type = "histogram", fill="cyan")

ggMarginal(g, type = "boxplot", fill="transparent")

ggMarginal(g, type = "density", fill="transparent")

# A frequency plot
options(repr.plot.width = 13, repr.plot.height = 7)
ggplot(data = df, aes(x = gender))+
    geom_bar(aes(fill = clicked_on_ad))+
    labs(title = 'Gender, clicked on ad Frequency', y = 'Frequency', x = 'Gender', fill = 'Clicked on ad') +
    scale_color_brewer(palette = 'cool') +
    theme(plot.title = element_text(size = 18, face = 'bold', color = 'darkmagenta'),
             axis.title.x = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.title.y = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.text.x = element_text(size = 13),
             axis.text.y = element_text(size = 13),
             legend.title = element_text(size = 13, color = 'darkmagenta'),
             legend.text = element_text(size = 12))
Unknown palette cool

# Plotting a a pair of histograms
options(repr.plot.width = 13, repr.plot.height = 7)
ggplot(data = df, aes(x = age, fill = clicked_on_ad))+
    geom_histogram(bins = 35, color = 'cyan') + 
    labs(title = 'Age distribution', x = 'Age', y = 'Frequency', fill = 'Clicked on ad') +
        scale_color_brewer(palette = 'Set1') +
        theme(plot.title = element_text(size = 18, face = 'bold', color = 'darkmagenta'),
             axis.title.x = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.title.y = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.text.x = element_text(size = 13, angle = 0),
             axis.text.y = element_text(size = 13),
             legend.title = element_text(size = 13, color = 'darkmagenta'),
             legend.text = element_text(size = 12))

# Frequency polygon
options(repr.plot.width = 13, repr.plot.height = 7)
ggplot(data = df, aes(x = area_income, col = clicked_on_ad))+
    geom_freqpoly(bins = 50)+
    labs(title = 'Frequency polygon : Area income vs clicked on ad', x = 'Area income', y = 'clicked on ad', fill = 'Clicked on ad') +
        scale_color_brewer(palette = 'Set1') +
        theme(plot.title = element_text(size = 18, face = 'bold', color = 'darkmagenta'),
             axis.title.x = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.title.y = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.text.x = element_text(size = 13),
             axis.text.y = element_text(size = 13),
             legend.title = element_text(size = 13, color = 'darkmagenta'),
             legend.text = element_text(size = 12))

# Plotting density plot
options(repr.plot.width = 13, repr.plot.height = 7)
p1 = ggplot(data = df, aes(age)) +
        geom_density(aes(fill=factor(clicked_on_ad)), alpha = 0.8) +
        labs(title = 'Clicked on ad density plot', x = 'Age', y = 'Density', fill = 'Clicked on ad') +
        scale_color_brewer(palette = 'cool') +
        theme(plot.title = element_text(size = 18, face = 'bold', color = 'darkmagenta'),
             axis.title.x = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.title.y = element_text(size = 15, face = 'bold', color = 'darkmagenta'),
             axis.text.x = element_text(size = 13, angle = 0),
             axis.text.y = element_text(size = 13),
             legend.title = element_text(size = 13, color = 'darkmagenta'),
             legend.text = element_text(size = 12))
Unknown palette cool
plot(p1)

# multivariate analysis
# a correlation matrix showing the correlation between each variable
library(ggcorrplot)
corr = round(cor(select_if(df, is.numeric)), 2)
ggcorrplot(corr, hc.order = T, ggtheme = ggplot2::theme_grey,
   colors = c("cyan", "peachpuff4", "pink"), lab = T)

# Pairplot
pairs(df[,c(1,2,3,4)])

LS0tCmF1dGhvcjogIlN0ZXBoYW5pZSBPbXdhbmRhIgp0aXRsZTogIlIgTm90ZWJvb2siCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQojIGxvYWQgbGlicmFyaWVzCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmBgYAoKYGBge3J9CiMgTG9hZGluZyB0aGUgY3N2IGZpbGUKZGYgPSByZWFkX2NzdignYWR2ZXJ0aXNpbmcuY3N2JykKCiMgUHJldmlld2luZyB0aGUgZmlyc3QgZml2ZSByb3dzIG9mIHRoZSBkYXRhZnJhbWUKaGVhZChkZikKYGBgCmBgYHtyfQojIHNob3cgaW5mb3JtYXRpb24gb24gZGF0YXNldApzdHIoZGYpCmBgYApgYGB7cn0KIyBjaGVja2luZyBmb3IgdGhlIHN0YXRpc3RpY2FsIHN1bW1hcnkKc3VtbWFyeShkZikKYGBgCmBgYHtyfQojIGRldGVybWluZSB0aGUgZGltZW5zaW9ucyBvZiB0aGUgZGF0YXNldCAKZGltKGRmKQpgYGAKVGhlIGRhdGFzZXQgaXMgc2VlbiB0byBoYXZlIDEwMDAgb2JzZXJ2YXRpb25zIGFuZCAxMCB2YXJpYWJsZXMuCmBgYHtyfQojIGNoZWNraW5nIGlmIHRoZXJlIGV4aXN0cyBudWxsIHZhbHVlcyBieSBjYWxjdWxhdGluZyB0aGUgc3VtIG9mIHRoZSBudWxsIHZhbHVlcyBwZXIgY29sdW1uIApjb2xTdW1zKChpcy5uYShkZikpKQpgYGAKYGBge3J9CiMgYSBwbG90IHNob3dpbmcgbWlzc2luZyB2YWx1ZXMKbGlicmFyeShEYXRhRXhwbG9yZXIpCnBsb3RfbWlzc2luZyhkZikKYGBgCgpgYGB7cn0KIyBjaGVja2luZyBmb3IgZHVwbGljYXRlcyBpbiB0aGUgZGF0YXNldCBieSBhc3NpZ25pbmcgYSB2YXJpYWJsZSAnZHVwbGljYXRlcycKZHVwbGljYXRlcyA8LSBkZltkdXBsaWNhdGVkKGRmKSxdCmR1cGxpY2F0ZXMKYGBgCmBgYHtyfQojIFBsb3R0aW5nIGJveHBsb3RzCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gMTMsIHJlcHIucGxvdC5oZWlnaHQgPSA3KQpnZ3Bsb3QoZGF0YSA9IGRmLCBhZXMoeCA9IGdlbmRlciwgeSA9IGRhaWx5X2ludGVybmV0X3VzYWdlKSkgKyAKICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IGZhY3RvcihjbGlja2VkX29uX2FkKSkpICsgCiAgICBsYWJzKHRpdGxlID0gJ0RhaWx5IGludGVybmV0IHVzYWdlIFZzIEdlbmRlcicsIHkgPSAnRGFpbHkgaW50ZXJuZXQgdXNhZ2UnLCB4ID0gJ0dlbmRlcicsIGZpbGwgPSAnQ2xpY2tlZCBvbiBhZCcpICsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gJ2Nvb2wnKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICdib2xkJywgY29sb3IgPSAnZGFya21hZ2VudGEnKSwKICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAnYm9sZCcsIGNvbG9yID0gJ2RhcmttYWdlbnRhJyksCiAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gJ2JvbGQnLCBjb2xvciA9ICdkYXJrbWFnZW50YScpLAogICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwKICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksCiAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLCBjb2xvciA9ICdkYXJrbWFnZW50YScpLAogICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkKYGBgCgpgYGB7cn0KIyBhIHBsb3Qgc2hvd2luZyBpbmNvbWUgdXNhZ2UgaW4gcmVsYXRpb24gdG8gZ2VuZGVyCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gMTMsIHJlcHIucGxvdC5oZWlnaHQgPSA3KQpnZ3Bsb3QoZGF0YSA9IGRmLCBhZXMoeCA9IGdlbmRlciwgeSA9IGFyZWFfaW5jb21lKSkgKyAKICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IGZhY3RvcihjbGlja2VkX29uX2FkKSkpICsgCiAgICBnZW9tX2RvdHBsb3QoYmlud2lkdGggPSBOVUxMLCBiaW5heGlzID0gJ3knLCBzdGFja2RpciA9ICdjZW50ZXInLCBkb3RzaXplID0gLjUsIGZpbGwgPSAnbWFyb29uJykgKwogICAgbGFicyh0aXRsZSA9ICdBcmVhIGluY29tZSB1c2FnZSBWcyBHZW5kZXInLCB5ID0gJ0FyZWEgaW5jb21lJywgeCA9ICdHZW5kZXInLCBmaWxsID0gJ0NsaWNrZWQgb24gYWQnKSArCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICdjb29sJykgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhY2UgPSAnYm9sZCcsIGNvbG9yID0gJ2RhcmttYWdlbnRhJyksCiAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gJ2JvbGQnLCBjb2xvciA9ICdkYXJrbWFnZW50YScpLAogICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICdib2xkJywgY29sb3IgPSAnZGFya21hZ2VudGEnKSwKICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksCiAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMpLAogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMywgY29sb3IgPSAnZGFya21hZ2VudGEnKSwKICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpCmBgYApgYGB7cn0KIyBwbG90dGluZyBtdWx0aXBsZSBib3hwbG90cwpvcHRpb25zKHJlcHIucGxvdC53aWR0aCA9IDEzLCByZXByLnBsb3QuaGVpZ2h0ID0gNykKYm94cGxvdChkZiRkYWlseV90aW1lX3NwZW50X29uX3NpdGUsIGRmJGFnZSwgZGYkZGFpbHlfaW50ZXJuZXRfdXNhZ2UsCm1haW4gPSAiTXVsdGlwbGUgYm94cGxvdHMgZm9yIGNvbXBhcmlzaW9uIiwKYXQgPSBjKDEsMiwzKSwKbmFtZXMgPSBjKCJTaXRlIiwgIkFnZSIsIlVzYWdlIiksCmxhcyA9IDIsCmNvbCA9IGMoImRhcmttYWdlbnRhIiwiZGFya2dyZWVuIiwieWVsbG93IiksCmJvcmRlciA9ICJibHVlIiwKaG9yaXpvbnRhbCA9IFRSVUUsCm5vdGNoID0gVFJVRQopCmBgYAoKYGBge3J9CiMgVGhlIG1hbGUgY29sdW1uIHNob3VsZCBiZSByZW5hbWVkIHRvIGdlbmRlcgpjb2xuYW1lcyhkZilbY29sbmFtZXMoZGYpID09ICdtYWxlJ10gPSAnZ2VuZGVyJwpgYGAKCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCiMgQ2hhbmdpbmcgY29sdW1uIG5hbWVzIHRvIGxvd2VyIGNhc2UKY29sbmFtZXMoZGYpID0gdG9sb3dlcihzdHJfcmVwbGFjZV9hbGwoY29sbmFtZXMoZGYpLCBjKCcgJyA9ICdfJykpKQoKIyBDaGVja2luZyB3aGV0aGVyIHRoZSBjb2x1bW4gbmFtZXMgaGF2ZSBiZWVuIHJlbmFtZXMgYXBwcmlvcHJpYXRlbHkKcHJpbnQoY29sbmFtZXMoZGYpKQpgYGAKYGBge3J9CiMgQ2hlY2tpbmcgdGhlIGRhdGF0eXBlcyBmb3IgZWFjaCBjb2x1bW4KCmNvbHVtbnMgPSBjb2xuYW1lcyhkZikKZm9yIChjb2x1bW4gaW4gc2VxKGxlbmd0aChjb2xuYW1lcyhkZikpKSl7CiAgICBwcmludChjb2x1bW5zW2NvbHVtbl0pCiAgICBwcmludChzdHIoZGZbLCBjb2x1bW5dKSkKICAgIGNhdCgnXG4nKQp9CmBgYApgYGB7cn0KbGlicmFyeShtYWdyaXR0cikKIyBDaGFuZ2luZyBjb2x1bW4gbmFtZXMgdG8gdGhlaXIgYXBwcmlvcHJpYXRlIGRhdGEgdHlwZQojIENyZWF0aW5nIGEgbGlzdHMgb2YgY2F0ZWdvcmljYWwgYW5kIG51bWVyaWNhbCBjb2x1bW5zIAoKIyBMaXN0IG9mIGNhdGVnb3JpY2FsIGNvbHVtbnMKY2F0X2NvbHMgPSBjKCJhZF90b3BpY19saW5lIiwgImNpdHkiLCAiZ2VuZGVyIiwgImNvdW50cnkiLCAiY2xpY2tlZF9vbl9hZCIgKQoKIyBMaXN0IG9mIG51bWVyaWNhbCBjb2x1bW5zCm51bV9jb2xzID0gYygiZGFpbHlfdGltZV9zcGVudF9vbl9zaXRlIiwgImFnZSIsICJhcmVhX2luY29tZSIsICJkYWlseV9pbnRlcm5ldF91c2FnZSIpCgojIENoYW5naW5nIGNvbHVtbnMgdG8gZmFjdG9ycwpkZlssY2F0X2NvbHNdICU8PiUgbGFwcGx5KGZ1bmN0aW9uKHgpIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoeCkpKQpgYGAKCmBgYHtyfQojIENoZWNraW5nIHdoZXRoZXIgdGhlIGRhdGF0eXBlcyBmb3IgZWFjaCBjb2x1bW4gaGF2ZSBiZWVuIGNoYW5nZWQgYXBwcmlwcHJpYXRlbHkKY29sdW1ucyA9IGNvbG5hbWVzKGRmKQpmb3IgKGNvbHVtbiBpbiBzZXEobGVuZ3RoKGNvbG5hbWVzKGRmKSkpKXsKICAgIHByaW50KGNvbHVtbnNbY29sdW1uXSkKICAgIHByaW50KHN0cihkZlssIGNvbHVtbl0pKQogICAgcHJpbnQobmxldmVscyhkZlssIGNvbHVtbl0pKQogICAgY2F0KCdcbicpCn0KYGBgCgpgYGB7cn0KIyBGcmVxdWVuY3kgdGFibGVzCiMgMC1mZW1hbGUsIDEtbWFsZQpsZXZlbHMoZGYkZ2VuZGVyKSA9IGMoIkZlbWFsZSIsICJNYWxlIikKdGFibGUoZGYkZ2VuZGVyKQpgYGAKVGhlIGdlbmRlciBjb2x1bW4gaXMgc2VlbiB0byBiZSBhbG1vc3QgZXZlbmx5IGRpc3RyaWJ1dGVkIHdpdGggRmVtYWxlcyBiZWluZyBzbGlnaHRseSBoaWdoZXIgdGhhbiB0aGUgbWFsZXMuCmBgYHtyfQojMC15ZXMsMS1ubwpsZXZlbHMoZGYkY2xpY2tlZF9vbl9hZCkgPSBjKCJZZXMiLCAiTm8iKQp0YWJsZShkZiRjbGlja2VkX29uX2FkKQpgYGAKCiMjIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMKI1RoaXMgaXMgd2hlcmUgd2UgZXhwbG9yZSB0aGUgZGF0YSBzbyBhcyB0bzoKKm1heGltaXplIGluc2lnaHRzIG9uIHRoZSBkYXRhIHNldAoqdW5jb3ZlciB1bmRlcmx5aW5nIHN0cnVjdHVyZQoqZXh0cmFjdCBpbXBvcnRhbnQgdmFyaWFibGVzCipkZXRlY3Qgb3V0bGllcnMgYW5kIGFub21hbGllcwoqdGVzdCB1bmRlcmx5aW5nIGFzc3VtcHRpb25zCipkZXZlbG9wIG1vZGVscyB3aXRoIGdyZWF0IGV4cGxhbmF0b3J5IHByZWRpY3RpdmUgcG93ZXIKKmRldGVybWluZSBvcHRpbWFsIGZhY3RvciBzZXR0aW5ncwoKSGVyZSB3ZSB3aWxsIHBlcmZvcm0gOgp1bml2YXJpYXRlIGFuYWx5c2lzCmJpdmFyaWF0ZSBhbmFseXNpcwptdWx0aXZhcmlhdGUgYW5hbHlzaXMKCmBgYHtyfQojIERhaWx5IHRpbWUgc3BlbnQgb24gc2l0ZSBkaXN0cmlidXRpb24KIwp4ID0gaGlzdChkZiRkYWlseV90aW1lX3NwZW50X29uX3NpdGUsCiAgICAgICAgIG1haW4gPSAiRGFpbHkgdGltZSBTcGVudCBvbiBTaXRlIiwKICAgICAgICAgeGxhYiA9ICJEYWlseSB0aW1lIFNwZW50IG9uIFNpdGUiLAogICAgICAgICBjb2wgPSAiY3lhbiIsCikKc3VtbWFyeShkZiRkYWlseV90aW1lX3NwZW50X29uX3NpdGUpCmBgYApgYGB7cn0KIyBBZ2UgZGlzdHJpYnV0aW9uIHBsb3QKIwp5ID0gaGlzdChkZiRhZ2UsCiAgICAgICAgIG1haW4gPSAiQWdlIGRpc3RyaWJ1dGlvbiIsCiAgICAgICAgIHhsYWIgPSAiQWdlIiwKICAgICAgICAgY29sID0gInB1cnBsZSIsCikKc3VtbWFyeShkZiRhZ2UpCgpgYGAKYGBge3J9CiMgYSBwbG90IHNob3dpbmcgYXJlYSBpbmNvbWUgZGlzdHJpYnV0aW9uCnogPSBoaXN0KGRmJGFyZWFfaW5jb21lLAogICAgICAgICBtYWluID0gIkFyZWEgSW5jb21lIGRpc3RyaWJ1dGlvbiIsCiAgICAgICAgIHhsYWIgPSAiQXJlYSIsCiAgICAgICAgIGNvbCA9ICJwaW5rIiwKKQpzdW1tYXJ5KGRmJGFyZWFfaW5jb21lKQoKYGBgCgpgYGB7cn0KI2RlbnNpdHkgcGxvdHMgZm9yIHVuaXZhcmlhdGUgYW5hbHlzaXMKbGlicmFyeShEYXRhRXhwbG9yZXIpCnBsb3RfZGVuc2l0eShkZikKYGBgCmBgYHtyfQojIGJpdmFyaWF0ZSBwbG90cwojIHNjYXR0ZXIgcGxvdHMKbGlicmFyeShEYXRhRXhwbG9yZXIpCiMgYSBzY2F0dGVyIHBsb3Qgc2hvd2luZyByZWxhdGlvbnMgYmV0d2VlbiBkYWlseSBpbnRlcm5ldCBhbmQgdGltZSBzcGVudCBvbiB0aGUgc2l0ZQp0aW1lc3BlbnQgPC0gZGYkZGFpbHlfdGltZV9zcGVudF9vbl9zaXRlCmludGVybmV0dXNhZ2U8LSBkZiRkYWlseV9pbnRlcm5ldF91c2FnZQpwbG90KHRpbWVzcGVudCwgaW50ZXJuZXR1c2FnZSwgeGxhYj0iRGFpbHkgdGltZSBzcGVudCBvbiBzaXRlIiwgeWxhYj0iRGFpbHkgSW50ZXJuZXQgVXNhZ2UiKQpgYGAKYGBge3J9CiMgYSBzY2F0dGVyIHBsb3Qgc2hvd2luZyByZWxhdGlvbnMgYmV0d2VlbiBpbnRlcm5ldCB1c2FnZSBhbmQgYXJlYSBpbmNvbWUKcGxvdChhcmVhX2luY29tZSB+IGRhaWx5X2ludGVybmV0X3VzYWdlLCBkYXRhID0gZGYpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5IChnZ0V4dHJhKQpvcHRpb25zKHJlcHIucGxvdC53aWR0aCA9IDEzLCByZXByLnBsb3QuaGVpZ2h0ID0gNykKZyA9IGdncGxvdChkYXRhID1kZiwgYWVzKHggPWFyZWFfaW5jb21lLCB5ID0gZGFpbHlfaW50ZXJuZXRfdXNhZ2UsIGNvbD0gY2xpY2tlZF9vbl9hZCkpICsgCiAgICBnZW9tX2NvdW50KCkgKyAKICAgIGxhYnModGl0bGUgPSAnQXJlYSBpbmNvbWUgVnMgRGFpbHkgaW50ZXJuZXQgdXNhZ2UnLCB5ID0gJ0RhaWx5IGludGVybmV0IHVzYWdlJywgeCA9ICdBcmVhIGluY29tZScsIGZpbGwgPSAnQ2xpY2tlZCBvbiBhZCcpICsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gJ1NldDEnKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICdib2xkJywgY29sb3IgPSAnZGFya21hZ2VudGEnKSwKICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAnYm9sZCcsIGNvbG9yID0gJ2RhcmttYWdlbnRhJyksCiAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gJ2JvbGQnLCBjb2xvciA9ICdkYXJrbWFnZW50YScpLAogICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwKICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksCiAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLCBjb2xvciA9ICdkYXJrbWFnZW50YScpLAogICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSkKCmdnTWFyZ2luYWwoZywgdHlwZSA9ICJoaXN0b2dyYW0iLCBmaWxsPSJjeWFuIikKZ2dNYXJnaW5hbChnLCB0eXBlID0gImJveHBsb3QiLCBmaWxsPSJ0cmFuc3BhcmVudCIpCmdnTWFyZ2luYWwoZywgdHlwZSA9ICJkZW5zaXR5IiwgZmlsbD0idHJhbnNwYXJlbnQiKQpgYGAKCmBgYHtyfQojIEEgZnJlcXVlbmN5IHBsb3QgaW4gcmVsYXRpb24gdG8gZ2VuZGVyCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gMTMsIHJlcHIucGxvdC5oZWlnaHQgPSA3KQpnZ3Bsb3QoZGF0YSA9IGRmLCBhZXMoeCA9IGdlbmRlcikpKwogICAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBjbGlja2VkX29uX2FkKSkrCiAgICBsYWJzKHRpdGxlID0gJ0dlbmRlciwgY2xpY2tlZCBvbiBhZCBGcmVxdWVuY3knLCB5ID0gJ0ZyZXF1ZW5jeScsIHggPSAnR2VuZGVyJywgZmlsbCA9ICdDbGlja2VkIG9uIGFkJykgKwogICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAnY29vbCcpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYWNlID0gJ2JvbGQnLCBjb2xvciA9ICdkYXJrbWFnZW50YScpLAogICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICdib2xkJywgY29sb3IgPSAnZGFya21hZ2VudGEnKSwKICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAnYm9sZCcsIGNvbG9yID0gJ2RhcmttYWdlbnRhJyksCiAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMpLAogICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwKICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGNvbG9yID0gJ2RhcmttYWdlbnRhJyksCiAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKQpgYGAKCmBgYHtyfQojIFBsb3R0aW5nIGEgYSBwYWlyIG9mIGhpc3RvZ3JhbXMKb3B0aW9ucyhyZXByLnBsb3Qud2lkdGggPSAxMywgcmVwci5wbG90LmhlaWdodCA9IDcpCmdncGxvdChkYXRhID0gZGYsIGFlcyh4ID0gYWdlLCBmaWxsID0gY2xpY2tlZF9vbl9hZCkpKwogICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDM1LCBjb2xvciA9ICdjeWFuJykgKyAKICAgIGxhYnModGl0bGUgPSAnQWdlIGRpc3RyaWJ1dGlvbicsIHggPSAnQWdlJywgeSA9ICdGcmVxdWVuY3knLCBmaWxsID0gJ0NsaWNrZWQgb24gYWQnKSArCiAgICAgICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAnU2V0MScpICsKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICdib2xkJywgY29sb3IgPSAnZGFya21hZ2VudGEnKSwKICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAnYm9sZCcsIGNvbG9yID0gJ2RhcmttYWdlbnRhJyksCiAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gJ2JvbGQnLCBjb2xvciA9ICdkYXJrbWFnZW50YScpLAogICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLCBhbmdsZSA9IDApLAogICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwKICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGNvbG9yID0gJ2RhcmttYWdlbnRhJyksCiAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKQpgYGAKYGBge3J9CiMgRnJlcXVlbmN5IHBvbHlnb24Kb3B0aW9ucyhyZXByLnBsb3Qud2lkdGggPSAxMywgcmVwci5wbG90LmhlaWdodCA9IDcpCmdncGxvdChkYXRhID0gZGYsIGFlcyh4ID0gYXJlYV9pbmNvbWUsIGNvbCA9IGNsaWNrZWRfb25fYWQpKSsKICAgIGdlb21fZnJlcXBvbHkoYmlucyA9IDUwKSsKICAgIGxhYnModGl0bGUgPSAnRnJlcXVlbmN5IHBvbHlnb24gOiBBcmVhIGluY29tZSB2cyBjbGlja2VkIG9uIGFkJywgeCA9ICdBcmVhIGluY29tZScsIHkgPSAnY2xpY2tlZCBvbiBhZCcsIGZpbGwgPSAnQ2xpY2tlZCBvbiBhZCcpICsKICAgICAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICdTZXQxJykgKwogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYWNlID0gJ2JvbGQnLCBjb2xvciA9ICdkYXJrbWFnZW50YScpLAogICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICdib2xkJywgY29sb3IgPSAnZGFya21hZ2VudGEnKSwKICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAnYm9sZCcsIGNvbG9yID0gJ2RhcmttYWdlbnRhJyksCiAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMpLAogICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwKICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGNvbG9yID0gJ2RhcmttYWdlbnRhJyksCiAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKQpgYGAKYGBge3J9CiMgUGxvdHRpbmcgZGVuc2l0eSBwbG90Cm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gMTMsIHJlcHIucGxvdC5oZWlnaHQgPSA3KQpwMSA9IGdncGxvdChkYXRhID0gZGYsIGFlcyhhZ2UpKSArCiAgICAgICAgZ2VvbV9kZW5zaXR5KGFlcyhmaWxsPWZhY3RvcihjbGlja2VkX29uX2FkKSksIGFscGhhID0gMC44KSArCiAgICAgICAgbGFicyh0aXRsZSA9ICdDbGlja2VkIG9uIGFkIGRlbnNpdHkgcGxvdCcsIHggPSAnQWdlJywgeSA9ICdEZW5zaXR5JywgZmlsbCA9ICdDbGlja2VkIG9uIGFkJykgKwogICAgICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gJ2Nvb2wnKSArCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhY2UgPSAnYm9sZCcsIGNvbG9yID0gJ2RhcmttYWdlbnRhJyksCiAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gJ2JvbGQnLCBjb2xvciA9ICdkYXJrbWFnZW50YScpLAogICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICdib2xkJywgY29sb3IgPSAnZGFya21hZ2VudGEnKSwKICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMywgYW5nbGUgPSAwKSwKICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksCiAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLCBjb2xvciA9ICdkYXJrbWFnZW50YScpLAogICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkKcGxvdChwMSkKYGBgCmBgYHtyfQojIG11bHRpdmFyaWF0ZSBhbmFseXNpcwojIGEgY29ycmVsYXRpb24gbWF0cml4IHNob3dpbmcgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gZWFjaCB2YXJpYWJsZQpsaWJyYXJ5KGdnY29ycnBsb3QpCmNvcnIgPSByb3VuZChjb3Ioc2VsZWN0X2lmKGRmLCBpcy5udW1lcmljKSksIDIpCmdnY29ycnBsb3QoY29yciwgaGMub3JkZXIgPSBULCBnZ3RoZW1lID0gZ2dwbG90Mjo6dGhlbWVfZ3JleSwKICAgY29sb3JzID0gYygiY3lhbiIsICJwZWFjaHB1ZmY0IiwgInBpbmsiKSwgbGFiID0gVCkKYGBgCmBgYHtyfQojIFBhaXJwbG90CnBhaXJzKGRmWyxjKDEsMiwzLDQpXSkKYGBgCgo=